package com.decent.ejfadmin.auth;


import cn.decent.component.shiro.entity.Admin;
import cn.decent.component.shiro.service.AdminService;
import com.decent.ejfadmin.utils.Md5;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.*;

/**
 * API接口验证AOP
 *
 * @author 王元鑫
 */
//@Component
@Aspect
public class ApiVerificationAspect {
    private static final Logger log = LoggerFactory.getLogger(ApiVerificationAspect.class);
    private static final String KEY = "e1e5966d3375d9979a84cc4ffac5f9b112d6500828c9d5b63848117e";
    @Autowired
    private AdminService adminService;

    @Pointcut("execution(@com.decent.ejfadmin.auth.ApiVerification * *(..))")
    private void verifySign() {
    }

    @Around("verifySign()")
    public Object doBasicProfiling(ProceedingJoinPoint pjp) {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        try {
            try {
                Admin currentUser = adminService.getCurrentAdmin();
                if (Objects.nonNull(currentUser)) {
                    return pjp.proceed();
                }
            } catch (Exception e) {
                //这里是无法获取到用户信息,则走判定
            }
            //获取参数
            Enumeration<String> parameterNames = request.getParameterNames();
            List<String> keyParams = new ArrayList<>(10);
            while (parameterNames.hasMoreElements()) {
                String param = parameterNames.nextElement();
                if (StringUtils.equals("times", param)) {
                    //时间戳5分钟超时验证
                    long time = System.currentTimeMillis() - Long.parseLong(request.getParameter(param));
                    if (time > 5 * 60 * 1000 || time < -5 * 60 * 1000) {
                        log.warn("链接超时 {}|{}", request.getRequestURI(), request.getParameterMap());
                        return getAopReturn("overTime Error");
                    }
                } else if (StringUtils.equals(param, "sign") || StringUtils.isEmpty(request.getParameter(param))) {
                    continue;
                }
                keyParams.add(param + request.getParameter(param));
            }
            Collections.sort(keyParams, String.CASE_INSENSITIVE_ORDER);
            String s = StringUtils.join(keyParams, "") + KEY;
            String md5 = Md5.getMd5(s, true, "UTF-8");
            if (!StringUtils.equalsIgnoreCase(md5, request.getParameter("sign"))) {
                log.warn("公共签名错误加密原文[{}]加密结果[{}]", s, md5);
                return getAopReturn("verification error");
            }
            return pjp.proceed();
        } catch (Throwable e) {
            log.warn("api接口签名验证aop异常[{}]", e.getLocalizedMessage(), e);
            return getAopReturn("system error");
        }
    }

    private Object getAopReturn(String message) {
        try {
            HttpServletResponse response = SysContent.getResponse();
            ServletOutputStream out = response.getOutputStream();
            IOUtils.write(message, out, "UTF-8");
            IOUtils.closeQuietly(out);
        } catch (Exception e) {
            log.warn("切面返回发生异常[{}]", e.getLocalizedMessage(), e);
        }
        return null;
    }
}
